home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr05 / xnot12a.zip / MAIN.C < prev    next >
C/C++ Source or Header  |  1993-06-16  |  22KB  |  901 lines

  1. #include "jam.h"
  2. #include "stdlib.h"
  3.  
  4. /*
  5.  *        Mainline
  6.  */
  7. #include "stdio.h"
  8. #include "def.h"
  9. #include "keyname.h"
  10. #include "kbd.h"
  11. #include "macro.h"
  12. #include "malloc.h"
  13. #ifdef SomeUnix
  14. # include <unistd.h>
  15. #endif
  16. #ifdef FAT
  17. # include <io.h>
  18. #endif
  19.  
  20. int preload_ = TRUE;            /* bad location, control prompt-preload */
  21. int    thisflag;            /* Flags, this command        */
  22. int    lastflag;            /* Flags, last command        */
  23. int    curgoal;            /* Goal column            */
  24. BUFFER    *curbp;                /* Current buffer        */
  25. EWINDOW    *curwp;                /* Current window        */
  26. BUFFER    *bheadp;            /* BUFFER listhead        */
  27. EWINDOW    *wheadp = (EWINDOW *)NULL;    /* WINDOW listhead        */
  28. char    pat[NPAT];            /* Pattern            */
  29. char *homedir;
  30. BOOL showtouchedlines = TRUE;
  31. BOOL somemail = FALSE;
  32. char *g_APPNAME = AppName;
  33.  
  34. #ifndef WINDOWED
  35.  static char startdir[NFILEN];    /* original directory */
  36. #endif
  37.  
  38. extern char prompt[], *promptp;    /* delayed prompting */
  39.  
  40. #define ALIVE 0
  41. #define DIED  1
  42. #define KILLED 2
  43. static killed = ALIVE;
  44.  
  45. static VOID rn_(edinit,(void));
  46. static int rn_(ReadAlarmFile, (char *dir, BOOL append));
  47.  
  48. static char *path;            /* point to startup dir */
  49.  
  50. /* Change the entry point to allow various Window-based pre-startup
  51. * code to be executed first. Don't forget, if running in a Window,
  52. * EMACS thinks the window is just a terminal, and we like it that way.
  53. * This EMACS is minimally Windows-aware...
  54. */
  55. #ifdef WINDOWED
  56.  VOID EmaxMain(argc, argv)
  57. #else
  58.  VOID main(argc, argv)
  59. #endif
  60. int  argc;
  61. char **argv;
  62. {
  63.     char    *cp, *loadfile = NULL;
  64.         BOOL flag;
  65.  
  66.     /* parse incoming args for startup dir
  67.         */
  68.         path = (char *)0;
  69.         if (argv[0] && *argv[0])   /* our EXE name */
  70.       {
  71.       register int i;
  72.  
  73.       path = argv[0];
  74.       i = strlen(path)-1; 
  75.  
  76.       /* go to first \ backwards
  77.           */
  78.           for (; path[i]; i--)
  79.             if (path[i] == BDC1)
  80.           {
  81.         path[i+1] = '\0';
  82.         break;
  83.           }
  84.           }
  85.  
  86.         /* see if can find home    
  87.         */
  88.         homedir = getenv("HOME");
  89.         if (!homedir || !*homedir)    /* try to make sure have one! */
  90.       homedir = path;
  91.         if (!homedir || !*homedir)
  92.           {
  93.            static char lastresort[2];
  94.            
  95.            lastresort[0] = BDC1;
  96.            lastresort[1] = '\0';
  97.        homedir = lastresort;
  98.           }
  99.  
  100. #ifdef SYSINIT
  101.     SYSINIT;                /* system dependent.    */
  102. #endif
  103.     vtinit();                /* Virtual terminal.    */
  104.     dirinit();                /* Get current directory */
  105. #ifndef WINDOWED
  106.         /* In DOS land, want to restore original
  107.         * directory to shell on exit (needed since each
  108.         * buffer causes chdir to happen)
  109.         */
  110.         if (wdir && *wdir)
  111.           strcpy(startdir, wdir);
  112. #endif
  113.     edinit();                /* Buffers, windows.    */
  114.     ttykeymapinit();            /* Symbols, bindings.    */
  115.  
  116.     /* Doing update() before reading files causes the error messages from
  117.      * the file I/O to show up on the screen(and also an extra display
  118.      * of the mode line if there are files specified on the command line).
  119.      */
  120.     update();
  121.  
  122.     if ((cp = startupfile(path)) != NULL)
  123.       (VOID) load(loadfile = cp);
  124.  
  125.         flag = FALSE;
  126.     while (--argc > 0) {
  127.         cp = adjustname(*++argv);
  128.         curbp = findbuffer(cp);
  129.         (VOID) showbuffer(curbp, curwp, 0);
  130.         (VOID) readin(cp);
  131.             if (fileisrdonly(cp))
  132.                  curbp->b_flag |= BFVIEW;
  133.               cmodename(curbp, cp);
  134.                 flag = TRUE;
  135.     }
  136.     thisflag = 0;            /* Fake last flags.    */
  137.  
  138.     /* got a file so can kill scratch 
  139.         */
  140.     if (flag)
  141.           {
  142.             BUFFER *bp;
  143.  
  144.             if (bp = bfind(Scratch, FALSE))
  145.               nukebuffer(bp);
  146.           }
  147.  
  148. #ifdef MSW
  149.         /* These msgs for my own happiness; however, if not
  150.         * here, the insert point incorrectly shows up in col 0
  151.         * of the echo line, but it is a display bug only. Don't 
  152.         * have a clue why though...some kind of timing problem no doubt.
  153.         */
  154.         ewprintf("Home dir: %s", homedir);
  155.         sleep(1);
  156.         if (loadfile)
  157.           {
  158.             ewprintf("Startup file %s", loadfile);
  159.             sleep(1);
  160.           }
  161.  
  162.         /* Load any alarms after other startup complete
  163.         */
  164.         ReadAlarmFile(homedir, TRUE);
  165.         sleep(1);
  166.  
  167. #endif /* MSW */
  168.  
  169.         /* Check for a crash; can tell if the log file
  170.          * was not cleaned up.
  171.          */
  172.         ExtendedFunction(function_name(crashcheck));
  173.  
  174.         /* As long as we live...
  175.         */
  176.         flag = FALSE;
  177.     for(; killed == ALIVE; ) 
  178.       {
  179.         *(promptp = prompt) = '\0';
  180.         if(epresf == KPROMPT) 
  181.         eerase();
  182.  
  183.             /* This MUST stay here.. I removed the call from a
  184.             * jillion places and put it here (1) because it is
  185.             * cleaner and (2) only the active buffer gets - in 
  186.             * its mode line, others get clear mode lines and so
  187.             * we need to update practically all the time. It is cheap
  188.             * anyway because the display code is quick enough, and
  189.             * really, how many windows do you have up?
  190.             */
  191.             upmodes(0);
  192.         update();
  193.  
  194.         lastflag = thisflag;
  195.         thisflag = 0;
  196.         switch(doin()) {
  197.         case TRUE: 
  198.             break;
  199.         case ABORT:
  200.             ewprintf("Quit");        /* and fall through    */
  201.         case FALSE:
  202.         default:
  203.             ttbeep();
  204.             macrodef = FALSE;
  205.         }
  206.         /* interrupted-prompts clear input buffer; reload
  207.         * with saved-off events; then check if cwd has changed
  208.         */
  209.         CheckForPutback();
  210.          switchdir(curbp);   /* based on current buffer's file path */
  211.  
  212.             /* update visible buffer list
  213.             */
  214.             if ((thisflag & CFKILLB) || (thisflag & CFNEWF) || 
  215.                 (thisflag & CFNEWB) || (thisflag & CFNEWC))
  216.               update_blist();
  217.  
  218.             /* Advertise
  219.             */
  220.             if (!flag)
  221.               {
  222.                 ExtendedFunction(function_name(showversion));
  223.                 flag = TRUE;
  224.               }
  225.     }
  226.  
  227.     /* Cleanup if all is ok; hard kill means leave inc files
  228.     * around, etc. (Not used much, mostly a debugging tool)
  229.     */
  230.     if (killed != KILLED)
  231.       ExitCleanup();
  232.  
  233. #ifndef WINDOWED
  234.     /* If got good start dir, reset now
  235.     */
  236.     if (startdir[0])
  237.       setdir(startdir);
  238. #endif
  239. }
  240.  
  241. /*
  242.  * Initialize default buffer and window.
  243.  */
  244. static VOID edinit() 
  245. {
  246.     register BUFFER *bp;
  247.     register EWINDOW *wp;
  248.  
  249.     bheadp = NULL;
  250.     bp = bfind(Scratch, TRUE);         /* Text buffer.    */
  251.     wp = (EWINDOW *)calloc(1,sizeof(EWINDOW)); /* Initial window.    */
  252.     if (bp==NULL || wp==NULL) 
  253.       panic("edinit");
  254.     curbp  = bp;                /* Current ones.    */
  255.     wheadp = wp;
  256.     curwp  = wp;
  257.     wp->w_wndp  = NULL;            /* Initialize window.    */
  258.     wp->w_bufp  = bp;
  259.     bp->b_nwnd  = 1;            /* Displayed.        */
  260.     wp->w_linep = wp->w_dotp = bp->b_linep;
  261.     wp->w_doto  = 0;
  262.     wp->w_markp = NULL;
  263.     wp->w_marko = 0;
  264.     wp->w_toprow = 0;
  265.     wp->w_ntrows = (char)(nrow-2);        /* 2 = mode, echo.    */
  266.     wp->w_force = 0;
  267.     wp->w_flag  = WFMODE|WFHARD;        /* Full.        */
  268. }
  269.  
  270. /*
  271.  * Quit command. If an argument, always
  272.  * quit. Otherwise confirm if a buffer has been
  273.  * changed and not written out. Normally bound
  274.  * to "C-X C-C".
  275.  */
  276. /*ARGSUSED*/
  277. quit(f, n)
  278. int f, n;
  279. {
  280.   register int    s;
  281.  
  282.   if ((s = anycb(FALSE)) == ABORT) 
  283.     return ABORT;
  284.   if (s == FALSE
  285.       || eyesno("Some modified buffers exist, really exit") == TRUE) 
  286.     {
  287.       vttidy();
  288. #ifdef    SYSCLEANUP
  289.       SYSCLEANUP;
  290. #endif
  291.       killed = DIED;
  292.    }
  293.   return TRUE;
  294. }
  295.  
  296. /*
  297.  * User abort. Should be called by any input routine that sees a C-g
  298.  * to abort whatever C-g is aborting these days. Currently does
  299.  * nothing.
  300.  */
  301. /*ARGSUSED*/
  302. ctrlg(f, n)
  303. int f, n;
  304. {
  305.   return ABORT;
  306. }
  307.  
  308. #ifdef JAM_
  309. /* perform the word wrap
  310. */
  311. dowordwrap(lp, s)
  312.   register LINE *lp;  /* current line */
  313.   register int s;     /* cursor offset */
  314.   {
  315.   register int q;
  316.   register int c;
  317.  
  318.   /* seek backwards to whitespace
  319.   */
  320.   for (q = s; q >= 0 && (c = lgetc(lp, q)) != ' ' && c != '\t'; q--)
  321.       ;
  322.  
  323.   if (q < 0)     /* can't split this line (no whitespace) */
  324.     return;
  325.  
  326.   curwp->w_doto = q;
  327.   newline();
  328.   lp = curwp->w_dotp;
  329.   curwp->w_doto = lp->l_used;
  330.   }
  331. #endif
  332.  
  333. /* return parsed/truncated startup path (app name removed)
  334. */
  335. char *apppath()
  336. {
  337.   return(path);
  338. }
  339. void disable_preload()
  340. {
  341.   preload_ = FALSE;
  342. }
  343. void enable_preload()
  344. {
  345.   preload_ = TRUE;
  346. }
  347. /* Called before exit to delete temp files; the 
  348. * point being if these files remain, then we
  349. * died ungracefully. at some time, need to 
  350. * tell user we found them...
  351. */
  352. void ExitCleanup()
  353. {
  354.   register BUFFER *bp;
  355.  
  356.   for (bp = bheadp; bp != NULL; bp = bp->b_bufp) 
  357.     if (bp->b_iname[0])
  358.        unlink(bp->b_iname);
  359.  
  360.   ewprintf("Cleaning up log(s)...");
  361.   RemoveIncSaveLog();
  362. }
  363.  
  364. /* kill emax hard!
  365. */
  366. int shootmedead(f, n)
  367. int f, n;
  368. {
  369.   killed = KILLED;
  370.   return(1);
  371. }
  372.  
  373. /* Support to manage a log of files
  374. * which currently have an incremental save file.
  375. * If we die hard (or the machine does), this
  376. * file will be found next start-up and we
  377. * can warn the user
  378. */
  379. #define UNSAVED "*Unsaved*"
  380. static void _makename(buf)
  381. char *buf;
  382. {
  383.   int j = strlen(homedir);
  384.   strcpy(buf, homedir);    /* where to look for file */
  385.   if (buf[j - 1] != BDC1)
  386.     {
  387.       buf[j] = BDC1;
  388.       buf[j+1] = '\0';
  389.     }
  390.   strcat(buf, AppName);
  391.   strcat(buf, ".inc");
  392.  
  393.   for (j = 0; buf[j] != '\0'; j++)
  394.     if (ISUPPER(buf[j]))
  395.       buf[j] = (char)TOLOWER(buf[j]);
  396. }
  397.  
  398. /* Check for existance of crash file on startup
  399. */
  400. int crashcheck(f, n)
  401. int f,n;
  402. {
  403.   char incSaveLog[NFILEN];
  404.  
  405.   _makename(incSaveLog);
  406.   if (fileisok(incSaveLog))
  407.     {
  408.       BUFFER *bp = bfind(incSaveLog, FALSE);
  409.       char *adjf;
  410.  
  411.       if (bp)
  412.         {
  413.           bp->b_flag &= ~(BFCHG | BFINC| BFSAVED);
  414.           nukebuffer(bp);
  415.         }
  416.  
  417.       AddString(incSaveLog); 
  418.       AddKchar(CCHR('J'));
  419.       poptofilequiet(0, 1);
  420.       adjf = adjustname(incSaveLog);
  421.  
  422.       if (bp = findexistingbuffer(adjf))
  423.         {
  424.           if((bp->b_modes[0] = name_mode(DiredStr)) == NULL) 
  425.             {
  426.           bp->b_modes[0] = &map_table[0];
  427.           ewprintf(modeerr, DiredStr);
  428.               nukebuffer(bp);
  429.               return (FALSE);
  430.             }
  431.  
  432.           strcpy(bp->b_bname, UNSAVED);
  433.           bp->b_fname[0] = '\0';
  434.           bp->b_flag |= (BFVIEW | BFREVERT);
  435.           bp->b_nmodes = 0;
  436.         }
  437.       else
  438.         ewprintf("Failed to init incremental log buffer");
  439.     }
  440.  
  441. #if 0  /* Need a way on UN*X to find another process */
  442.   WindowMessage("Is another editor already running?\n Backup log found...", 
  443.                 FALSE);
  444. #endif
  445.   return(1);
  446. }
  447.  
  448. /* Create a file in HOME which is a log of all
  449. * buffers which currently have a autosave file (*.%%*).
  450. * Make a line in the file for each buffer which has
  451. * the full path name. We will just display it for the user
  452. * on restart...
  453. */
  454. void MakeIncSaveLog()
  455. {
  456.   register BUFFER *bp;
  457.   char incSaveLog[NFILEN];
  458.   BOOL opened = FALSE;
  459.   char linebuf[NLINE];
  460.  
  461.   for (bp = bheadp; bp != NULL; bp = bp->b_bufp) 
  462.     if ((bp->b_iname[0]) && (bp->b_flag & BFSAVED))
  463.       { 
  464.       if (!opened)
  465.         {
  466.           RemoveIncSaveLog();        /* remove existing file now */
  467.           _makename(incSaveLog);
  468.  
  469.           if (ffwopen(incSaveLog) != FIOSUC)
  470.             {
  471.               ewprintf("Can't create incremental save log %s.", incSaveLog);
  472.           break;
  473.             }
  474.         }
  475.       opened = TRUE;
  476.  
  477.       /* write the real file name into the log; user can then do
  478.       * revert-to on this file
  479.       */
  480.       sprintf(linebuf, " %s ", bp->b_fname);
  481.       if (ffputline(linebuf, (int)strlen(linebuf)) != FIOSUC)
  482.         break;           /* incomplete file! gag */
  483.     }
  484.  if (opened)
  485.    ffclose();
  486.  else
  487.    RemoveIncSaveLog();    /* delete any log since nothing to remember */
  488. }
  489.  
  490. /* Nice (not crashed/killed) exit calls this and
  491. * we cleanup the log
  492. */
  493. void RemoveIncSaveLog()
  494. {
  495.   char incSaveLog[NFILEN];
  496.  
  497.   _makename(incSaveLog);
  498.   unlink(incSaveLog);
  499. }    
  500.  
  501. /* toggle state of show-touched-lines flag
  502. */
  503. int toggleshowtouched(f,n)
  504. int f,n;
  505. {
  506.   showtouchedlines = (showtouchedlines ? FALSE : TRUE);
  507.   ewprintf("Touched lines %s be highlite.", 
  508.             showtouchedlines ? "will" : "will not");
  509.   upmodes(WFHARD);
  510.  
  511.   return(TRUE);
  512. }
  513.  
  514. /*
  515. * All this stuff belongs somewhere else but I didn't
  516. * feel like creating a new file!
  517. */
  518. #define WILD 99
  519. #define IsWild(n) ((n) == WILD)
  520. #define IsMatch(n, m) (IsWild(n) || ((n) == (m))) 
  521. #define ALARM_EXT ".alr"
  522. #define MINLEN (2+1+2+1+2+1+2)
  523.  
  524. /* alarm def:  00 00 00 00  ""   mos,day,hour,min,msg
  525. *  99 means any mon/day/hour
  526. */
  527. typedef struct _anAlarm
  528.   {
  529.   struct _anAlarm *next;
  530.   BOOL fired;
  531.   struct tm theTime;
  532.   char *theMessage;
  533.   } AnAlarm;
  534. static AnAlarm *s_firstAlarm = (AnAlarm *)0;
  535.  
  536. #ifdef WINDOWED
  537.   /* The X11 version is pretty feeble at this time; it opens
  538.   * an empty window and counts on the window manager to
  539.   * put up the title. The Windows 3.x/NT version uses a real
  540.   * live message box 
  541.   */ 
  542. # ifdef SomeUnix
  543.    static char *alarmApp = "xnotalrm ";
  544. # else
  545.    static char *alarmApp = "notalarm ";
  546. # endif
  547. #endif
  548.  
  549. static AnAlarm *rn_(addalarm, (char *s));
  550. static void rn_(freealarms, (void));
  551. static BOOL rn_(loadalarms, (void));
  552.  
  553. int ManageAlarms(f, n)
  554. int f, n;
  555. {
  556. #ifndef WINDOWED
  557.   ewprintf("Alarms not available");
  558.   return(TRUE);
  559. #else
  560.   char cmd[NLINE * 2];
  561.   register int i, s;
  562.   BUFFER *bp;
  563.   AnAlarm *a;
  564.  
  565.   if ((s = ereply("[a]dd [c]ancel [l]oad [s]show: ", cmd, NLINE)) == TRUE)
  566.     {
  567.       for (i = 0; cmd[i]; i++)
  568.         if (ISUPPER(cmd[i]))
  569.          cmd[i] = (char)TOLOWER(cmd[i]);
  570.  
  571.       if (cmd[0] == 'a')
  572.         {
  573.           s = ereply("mos/day/hour/min/msg (99 99 99 00 ss): ", cmd, NLINE);
  574.           if (s == TRUE)
  575.             {
  576.               i = strlen(cmd) - 1;
  577.           
  578.           while (cmd[i] == ' ')
  579.             i--;
  580.           if (i >= 0)
  581.             cmd[i+1] = 0;        /* kill extra blanks at lines end */
  582.               if (strlen(cmd) < MINLEN)
  583.                 s = FALSE;
  584.               else 
  585.                 s = ((a = addalarm(cmd)) ? TRUE : FALSE);
  586.             }
  587.  
  588.           /* alarm added? if so, add to alarm file
  589.           */
  590.           if (s == TRUE)
  591.             {
  592.               char def[NFILEN];
  593.  
  594.               /* Find existing alarm buffer, else
  595.                * create it. Make sure it has a file name.
  596.                */
  597.               strcpy(def, g_APPNAME);
  598.               strcat(def, ALARM_EXT);
  599.               for (i = 0; def[i]; i++)
  600.                 if (ISUPPER(def[i]))
  601.                   def[i] = (char)TOLOWER(def[i]);
  602.               bp = bfind(def, TRUE);
  603.               if (s = (bp ? TRUE : FALSE))
  604.                 {
  605.                   if (bp->b_fname[0] == '\0')
  606.                     {
  607.                       strcpy(bp->b_fname, homedir);
  608.                       i = strlen(bp->b_fname);
  609.                       if (i && (bp->b_fname[i-1] != BDC1))
  610.                         bp->b_fname[i++] = BDC1;  
  611.                       bp->b_fname[i] = 0;
  612.                       strcat(bp->b_fname, def);
  613.                     }                    /* null buffer name */
  614.                   sprintf(cmd, "  %02d\t%02d\t%02d\t%02d\t%s",
  615.                           (IsWild(a->theTime.tm_mon) ? 
  616.                            WILD : a->theTime.tm_mon + 1),
  617.                           a->theTime.tm_mday,
  618.                           a->theTime.tm_hour,
  619.                           a->theTime.tm_min,
  620.                           a->theMessage);
  621.                   s = (addline(bp, cmd) != NULL) ? TRUE : FALSE;
  622.                   if (s)
  623.                     bp->b_flag |= BFCHG;
  624.                 }                    /* buffer found */
  625.             }                        /* alarm added */
  626.           if (s)
  627.             popbuf(bp);                    /* show buffer if ok */
  628.         }
  629.       else if (cmd[0] == 'c')
  630.         freealarms();        /* zap all alarms */
  631.       else if (cmd[0] == 'l')
  632.         s = loadalarms();    /* load a new alarm file */
  633.       else if (cmd[0] == 's')
  634.         {
  635.           bp = bfind("*alarms*", TRUE);
  636.           s = (bp ? TRUE : FALSE);
  637.           if (s)
  638.             {
  639.               register AnAlarm *a;
  640.  
  641.               bp->b_flag &= ~BFCHG;
  642.               bp->b_flag &= ~BFVIEW;
  643.               bclear(bp);
  644.               addline(bp, "Current alarms");
  645.               addline(bp, "--------------");
  646.               addline(bp, "  Mos\tDay\tHour\tMin\tMsg");
  647.               addline(bp, "  ---\t---\t----\t---\t---");
  648.               for (a = s_firstAlarm; a && s; a = a->next)
  649.                 {
  650.                   sprintf(cmd, "  %02d\t%02d\t%02d\t%02d\t%s",
  651.                          (IsWild(a->theTime.tm_mon) ? 
  652.                            WILD : a->theTime.tm_mon + 1),
  653.                          a->theTime.tm_mday,
  654.                          a->theTime.tm_hour,
  655.                          a->theTime.tm_min,
  656.                          a->theMessage);
  657.                   s = (addline(bp, cmd) != NULL) ? TRUE : FALSE;
  658.                 }
  659.               bp->b_flag |= BFVIEW;
  660.               bp->b_flag &= ~BFCHG;
  661.               s = (popbuf(bp) ? TRUE : FALSE);
  662.             }
  663.         }
  664.       else
  665.         s = FALSE;
  666.     }
  667.   return(s);
  668. #endif
  669. }
  670. void AnyPendingAlarms()
  671. {
  672. #ifdef WINDOWED
  673.   register AnAlarm *a;
  674.   char msg[NLINE];
  675.   long currtime;
  676.   struct tm *t;
  677.  
  678.   time(&currtime);
  679.   t = localtime(&currtime);
  680.   for (a = s_firstAlarm; a; a = a->next)
  681.    {
  682.      if (IsMatch(a->theTime.tm_mon, t->tm_mon) &&
  683.          IsMatch(a->theTime.tm_mday, t->tm_mday) &&
  684.          IsMatch(a->theTime.tm_hour, t->tm_hour) &&
  685.          (a->theTime.tm_min == t->tm_min) &&
  686.          !a->fired)
  687.       {
  688.         a->fired = TRUE;
  689.         strcpy(msg, alarmApp);
  690.         strcat(msg, a->theMessage);
  691.         if (!winspawn(msg, TRUE))
  692.           {  
  693.             /* dump this message and give up
  694.             */
  695.             char buffer[512];
  696.  
  697.             sprintf(buffer, "Alarm failed: %s", a->theMessage);
  698.             WindowMessage(buffer, FALSE);
  699.             break;
  700.           } 
  701.       }
  702.    }
  703. #endif
  704. }
  705. static int ReadAlarmFile(dir, append)
  706. char *dir;
  707. BOOL append;
  708. {
  709. #ifdef WINDOWED
  710.   char alarmfile[NFILEN];
  711.   char c;
  712.   int i;
  713.   register BUFFER *bp;
  714.   register LINE *lp;
  715.  
  716.   alarmfile[0] = '\0';        /* init empty string */
  717.   if (s_firstAlarm)
  718.     if (eyesno("Cancel existing alarms") == TRUE)
  719.       freealarms();
  720.  
  721.   if (append)            /* build name with dir */
  722.     {
  723.     if (dir)
  724.       {
  725.         int i;
  726.  
  727.         strcpy(alarmfile, dir);
  728.         i = strlen(alarmfile) - 1;
  729.         if (alarmfile[i] != BDC1)
  730.           {
  731.             i++;
  732.             alarmfile[i++] = BDC1;
  733.             alarmfile[i] = '\0';
  734.           }
  735.       }
  736.     strcat(alarmfile, g_APPNAME);
  737.     strcat(alarmfile, ALARM_EXT);
  738.     }
  739.   else                /* full name supplied */
  740.     strcpy(alarmfile, dir);
  741.  
  742.   for (i = 0; alarmfile[i]; i++)
  743.     if (ISUPPER(alarmfile[i]))
  744.       alarmfile[i] = (char)TOLOWER(alarmfile[i]);
  745.  
  746.   if (access(alarmfile, F_OK) == 0)
  747.     {
  748.       AddString(alarmfile);
  749.       AddKchar(CCHR('J'));
  750.  
  751.       if (poptofilehidden(0, 1) != TRUE)
  752.         return (FALSE);
  753.       bp = curbp;
  754.  
  755.       /* parse it
  756.       */
  757.       lp = lforw(bp->b_linep); 
  758.       for (; lp != bp->b_linep; lp = lforw(lp))
  759.        {
  760.          c = lgetc(lp, 0);
  761.          if ((c == ';') || (strlen(ltext(lp)) < MINLEN))
  762.            continue;
  763.          if (!addalarm(ltext(lp)))
  764.            {
  765.              ewprintf("Alarm error [%s]", ltext(lp));
  766.              return (FALSE);
  767.            }
  768.        }
  769.  
  770.       /* kill the window if created automagically
  771.       */
  772.       if (append)
  773.         { 
  774.           delwind(1, 0);
  775.           nukebuffer(bp);
  776.           bp = (BUFFER *)0;
  777.         }
  778.  
  779.       ewprintf("%s loaded.", alarmfile);
  780.       return (TRUE);
  781.     }
  782. #endif
  783.   return (FALSE);    
  784. }
  785.  
  786. #ifdef WINDOWED    
  787. /* Adds alarm to list.  Memory not freed up
  788. * by this code;  task exit assumed to
  789. * provide cleanup or memory freed when alarms cleared.
  790. */
  791. static AnAlarm *addalarm(l)
  792. char *l;
  793. {
  794.   AnAlarm *a, *tmp;
  795.   char *p, *f = "%d";
  796.   long currtime;
  797.   char *notOK = (char *)0;
  798.   struct tm timestruct, *tm;
  799.   char msg[NLINE];
  800.  
  801.   time(&currtime);
  802.   tm = localtime(&currtime);
  803.   timestruct = *tm;            /* use some info from sys clock */
  804.   strcpy(msg, l);
  805.  
  806.   p = msg;
  807.   while(*p && ISWHITE(*p)) p++;
  808.   sscanf(p, f, ×truct.tm_mon);
  809.  
  810.   while(*p && !ISWHITE(*p)) p++;
  811.   while(*p && ISWHITE(*p)) p++;
  812.   sscanf(p, f, ×truct.tm_mday);
  813.  
  814.   while(*p && !ISWHITE(*p)) p++;
  815.   while(*p && ISWHITE(*p)) p++;
  816.   sscanf(p, f, ×truct.tm_hour);
  817.  
  818.   while(*p && !ISWHITE(*p)) p++;
  819.   while(*p && ISWHITE(*p)) p++;
  820.  
  821.   sscanf(p, f, ×truct.tm_min);
  822.   while(*p && !ISWHITE(*p)) p++;
  823.   while(*p && ISWHITE(*p)) p++;
  824.  
  825.   if (timestruct.tm_mon != WILD)
  826.     timestruct.tm_mon -= 1;        /* mos from 0 to 11 */
  827.  
  828.   if (timestruct.tm_mon != WILD)
  829.     if ((timestruct.tm_mon < 0) || (timestruct.tm_mon > 11))
  830.       notOK = "month";
  831.  
  832.   if (!notOK)
  833.     if (timestruct.tm_mday != WILD)
  834.       if ((timestruct.tm_mday < 0) || (timestruct.tm_mday > 30))
  835.         notOK = "day";
  836.  
  837.   if (!notOK)
  838.     if (timestruct.tm_hour != WILD)
  839.       if ((timestruct.tm_hour < 0) || (timestruct.tm_hour > 23))
  840.         notOK = "hour";
  841.  
  842.   if (!notOK)
  843.     if ((timestruct.tm_min < 0) || (timestruct.tm_min > 59))
  844.       notOK = "minute";
  845.  
  846.   if (notOK)
  847.     {
  848.       ewprintf("Error in alarm %s [%s]", notOK, l);
  849.       return((AnAlarm *)0);
  850.     }
  851.  
  852.   /* get new struct
  853.   */
  854.   a = (AnAlarm *)calloc(1, sizeof(AnAlarm));
  855.   if (!s_firstAlarm)
  856.     s_firstAlarm = a;
  857.   else
  858.     {
  859.       for( tmp = s_firstAlarm; tmp->next; tmp = tmp->next)
  860.         ;
  861.       tmp->next = a;
  862.     }
  863.   a->theTime = timestruct;
  864.   if (!(p && *p))
  865.     p = "[no message]";
  866.  
  867.   a->theMessage = (char *)malloc(strlen(p) + 1);
  868.   strcpy(a->theMessage, p);
  869.   return (a);
  870. }
  871. static BOOL loadalarms()
  872. {
  873.   char fname[NFILEN];
  874.   int s;
  875.  
  876.   if ((s = ereply("Load alarm file: ", fname, NFILEN)) == TRUE)
  877.     s = ReadAlarmFile(fname, FALSE);
  878.   return (s);
  879. }
  880. static void freealarms()
  881. {
  882.   register AnAlarm *a, *tmp;
  883.  
  884.   if (a = s_firstAlarm)
  885.     {
  886.       for (; a; )
  887.         {
  888.           tmp = a->next;        /* next alarm */
  889.           if (a->theMessage)
  890.             free(a->theMessage);
  891.           free(a); 
  892.           a = tmp;
  893.         }
  894.       s_firstAlarm = (AnAlarm *)0;
  895.       ewprintf("Alarms cleared.");
  896.     }
  897.   else
  898.     ewprintf("No alarms set.");
  899. }
  900. #endif /* WINDOWED */
  901.